package com.car.common;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.math3.util.Pair;

import com.alibaba.fastjson.JSON;
import com.google.common.collect.Maps;
import com.stonehenge.backend.security.Authorisation;
import com.stonehenge.backend.security.Encodings;
import com.stonehenge.backend.tools.StaticToolit;
import com.utils.SystemClock;
import com.utils.TypeUtil;
import com.utils.thread.LineLogger;


/**
 * 精简controller的类，主要含：<BR>
 * 1 时间耗时戳<BR>
 * 2 resultMap->addExtraResult<BR>
 * 3 dataMap->addData<BR>
 * 有log、putFinalReturn、putDefaultReturn等方法，调用了CtrlerHeader的一些已有方法
 * 
 * @author hzfulingjin
 *
 */
public class Tidy extends CtrlerHeader {
    
    /**静态变量区*/
    //private static final Logger logger = LoggerFactory.getLogger(Tidy.class);
    private static final boolean useThread = true;
    public static final int CUR_METHOD_STACK = 2;
    public static String SUPER_USER = "sp_youche";
    public static String localIP_10=Authorisation._10_X_X_X;
    public static String secretkey = "uwfmf>/>4>4;B3";
   
    /**重要私有变量*/
    private Map<String, Object> result = new HashMap<String, Object>();
    private Map<String, Object> data = new HashMap<String, Object>();   
    private String className = "C";    
    private long tick;
    RequestInfo requestInfo;
    private int servType;
;
    
    /**公用变量*/
    public long start = SystemClock.now();
    public boolean flag=true;
    
    //构造函数=============================================================================================
    public Tidy(String className) {
        super();
        init(className,null, 0);
    }
    public Tidy(String className,HttpServletRequest request) {
        super();
        init(className,request, 0);        
    }
    public Tidy(String className,HttpServletRequest request,int servType) {
        super();
        init(className,request,servType);       
    }
    //静态static=============================================================================================
    public static String getCurrentClassAndMethodNames(int stackIndex) {//2才是调用该方法时候的位置
        StackTraceElement stack = Thread.currentThread().getStackTrace()[stackIndex];
        String clazz = stack.getClassName();
        String method = stack.getMethodName();
        if(clazz.contains("."))
            return "" + clazz.substring(clazz.lastIndexOf(".")+1) + "-" + ">" + method + "";
        else
            return "" + clazz + "-" + ">" + method + "";
    }

   
    
    //成员=============================================================================================
    
    /**
     * 初始化
     */
    public void init(String className,HttpServletRequest request,int servType) {
        this.tick = SystemClock.now();
        this.className = className;
        
        this.servType=servType;
        
        requestInfo = new RequestInfo(request);
        
        //统一打印
        logRequest(request);
    }    

    /**
     * 返回现在时刻
     * @return
     */
    public long getTick(){
        return SystemClock.now();
    }
    
    /**
     * 返回RequestInfo
     * @return
     */
    public RequestInfo getRequestInfo(){
    	return requestInfo;
    }

    /**
     * 打印基本信息，uid，udid，postbody之類
     * @param userid
     * @param uid
     * @param udid
     * @param method
     * @param postbody
     */
    public void logBasic(String userid, String uid, String udid, String method, String postbody) {
        LineLogger.log(String.format("[" + className + "] userid=%s,uid=%s,udid=%s,method=%s", userid, uid, udid, method),useThread);
        if(StaticToolit.isNotEmpty(postbody))
            LineLogger.log("[" + className + "] post= " + postbody,useThread);
        
        //String ipString = Authorisation.ipControal(request); 
    }
    
    /**
     * 打印其它参数
     * @param para
     */
    public void logPara(String...para) {
        if(para==null||para.length<1)
            return;
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < para.length; i++) {
            sb.append(para[i]);
            if(i>0)
                sb.append(",");
        }
        LineLogger.log(String.format("[" + className + "] Parameters: " + sb.toString()),useThread);
    }
    
    /**
     * 打印请求
     * @param request
     */
    public void logRequest(HttpServletRequest request) {
        if(request!=null)
        LineLogger.log(String.format("[" + className + "] [>>>Request:]%s:%s%s?%s,Session=%s,Method=%s,thisHost=%s,isAllowed=%b,\t[>>>Header:]%s", 
                request.getLocalAddr(),
                request.getLocalPort(),
                request.getRequestURI(),
                request.getQueryString(),
                request.getRequestedSessionId(),
                request.getSession().getId(), 
                request.getMethod(),
                localIP_10,
                /*CtrlerUtils.getUrl(request)*/
                requestInfo==null?null:(requestInfo.getHeaders() + " " + requestInfo.method)),
                useThread);
                //request.getSession().invalidate();
        else
            LineLogger.log("request=null!!!!", useThread);
    }

    /**
     * 中途异常方法，也包括空返回，调用了header的exceptionReturn
     * @param code
     * @param infoORmsg
     * @return
     */
    public Map<String, Object> putHalfWayOrExceptionReturn(int code, String... infoORmsg) {    
        tick =  System.currentTimeMillis() - tick;
        if(code == NORMALEMPTYCODE)
        	result= halfwayReturn(result, code, infoORmsg);
        else
        	result= exceptionReturn(result, code, infoORmsg);
        //统一打印
        LineLogger.log("[" + className +"] [<!<!<Return] putHalfWayOrExceptionReturn!!!" + " timecost=" + tick + "ms result=" + JSON.toJSONString(result),useThread);
        return result;//exceptionReturn(result, code, infoORmsg);
    }

    /**
     * 最终返回，带经验信息带返回
     * @param code
     * @return
     */
    public Map<String, Object> putFinalReturn(int code) {
        tick =  System.currentTimeMillis() - tick;
        String resJson0=JSON.toJSONString(result);
        result = finalReturns(result, data, tick, code);
        String resJson=JSON.toJSONString(result);

        //统一打印
        if(resJson!=null && resJson.length()>2048)
            LineLogger.log("[" + className + "] [<<<Return]timecost=" + tick + "ms result=" + resJson0 + " with data=" + "..." + resJson.length() + " Byte" ,useThread);
        else
            LineLogger.log("[" + className + "] [<<<Return]timecost=" + tick + "ms result=" + resJson,useThread);
        return result;
    }

    /**
     * data里面加数据，给前端用的
     * @param key
     * @param value
     */
    public void addData(String key, Object value) {
            data.put(key, value);
    }
    
    /**
     * 直接装入map
     * @param m
     */
    public void addData(Map<String, Object> m) {
    	if(m!=null)
    		data.putAll(m);
    }
    
    
    
    /**
     * 获取data
     * @param key
     * @return
     */
	public Object getData(String key) {

		return data.get(key);

	}
    
    /**
     * data里面加额外数据，给前端用的
     * @param key
     * @param value
     */
    @SuppressWarnings("unchecked")
	public void addData(String key, String exkey, Object value) {
		if (key == DATA_GLOBAL_EXTRA) {
			Map<String, Object> exMap = (Map<String, Object>) data.get(DATA_GLOBAL_EXTRA);
			if (exMap == null)
				data.put(DATA_GLOBAL_EXTRA, new HashMap<String, Object>());
			((Map<String, Object>) data.get(DATA_GLOBAL_EXTRA)).put(exkey, value);
		}

	}
    
    /**
     * listdata里面加数据，给前端用的,如果是null，就返回空的数组
     * @param key
     * @param value
     */
    public void addDataList(String key, Object value) {
    	if(value ==null)
            data.put(key, new ArrayList<String>());
    	else 
    		data.put(key, value);
    }


    /**
     * resultmp里面加额外数据， 自己看的
     * @param key
     * @param value
     */
    public void addExtraResult(String key, Object value) {
    	if(key.equalsIgnoreCase(RETURNTYPE_MSG) && value instanceof String){
    		if(!StaticToolit.isEmpty((String)value))
        		result.put(key, value);
    	}else
    		result.put(key, value);
    }

    /**存放额外信息，比如经验值的使用就是：
     *  tidy.addEx(RETURNTYPE_EX, exValue);
     * @param exKey
     * @param exValue
     */
    @SuppressWarnings("unchecked")
    public void addEx(String exKey,Object exValue) {
        Object oldMap = result.get(RETURNTYPE_EX);
        if (null == oldMap || !(oldMap instanceof Map)) {
            oldMap = new HashMap<String, Object>();
            result.put(RETURNTYPE_EX, oldMap);
        }
        HashMap<String, Object> map = (HashMap<String, Object>) oldMap;
        map.put(exKey, exValue);
    }

    public Long getUserid() {
        return Long.valueOf(requestInfo.getHeaders().get("uid"));
    }


    //class=============================================================================================
    public class RequestInfo {
        public final static String REQUESTINFO_HEADER_UDID = "udid";
        public final static String REQUESTINFO_HEADER_UID = "uid";
        public final static String REQUESTINFO_HEADER_TIMESTAMP = "timestamp";
        public final static String REQUESTINFO_HEADER_TOKEN = "token";
        public final static String REQUESTINFO_HEADER_SIGN = "sign";
        public final static String REQUESTINFO_HEADER_IP = "ip";
        public final static String REQUESTINFO_HEADER_USER_AGENT = "User-Agent";
        public final static String REQUESTINFO_HEADER_Content_MD5 = "Content-MD5";
        public final static String REQUESTINFO_HEADER_ContentType = "Content-Type";
        public final static String REQUESTINFO_HEADER_APPBUILD = "appbuild";

        private HttpServletRequest request;
        private Map<String, String> headers = Maps.newHashMap();
        private String method;

        public String pass = VERIFY_YES;
        public boolean superuser = false;

        public RequestInfo(HttpServletRequest request) {
            // super user
            SUPER_USER = "sp_youche" + StaticToolit.dayForWeek(System.currentTimeMillis());


            // request
            if (request == null) {
                pass = "request null";
                return;
            }
            this.request = request;

            // method
            this.method = request.getMethod();

            // pass or not
            try {
                pass = anaysisReq();
            } catch (Exception e) {
                pass = VERIFY_NO + ":" + e.getMessage();
            }

            // super user
            if (request.getParameter(REQUESTINFO_HEADER_SIGN) != null && SUPER_USER.equals(request.getParameter(REQUESTINFO_HEADER_SIGN)))
                superuser = true;
            else if (headers.get(REQUESTINFO_HEADER_SIGN) != null && SUPER_USER.equals(headers.get(REQUESTINFO_HEADER_SIGN)))
                superuser = true;
            // LineLogger.log("[" + className + "]" + " today superuser="+SUPER_USER + "|" + " superuser=" +
            // superuser,useThread);

            // LineLogger.log("[" + className + "] headers=" + headers, useThread);
        }

        public HttpServletRequest getRequest() {
            return request;
        }

        public void setRequest(HttpServletRequest request) {
            this.request = request;
        }

        public Map<String, String> getHeaders() {
            return headers;
        }

        public void setHeaders(Map<String, String> headers) {
            this.headers = headers;
        }


        public String getPlatform() {
            String User_Agent = request.getHeader(REQUESTINFO_HEADER_USER_AGENT);
            if (null != User_Agent) {
                if (User_Agent.toLowerCase().contains("android")) {
                    return "android";
                } else if (User_Agent.toLowerCase().contains("ios")) {
                    return "ios";
                }
            }
            return "unknow";
        }

        /**
         * 对请求的解析
         * 
         * @return
         */
        private String anaysisReq() {
            // header
            String udid = request.getHeader(REQUESTINFO_HEADER_UDID);
            String uid = request.getHeader(REQUESTINFO_HEADER_UID);
            String token = request.getHeader(REQUESTINFO_HEADER_TOKEN);
            String sign = request.getHeader(REQUESTINFO_HEADER_SIGN);
            String User_Agent = request.getHeader(REQUESTINFO_HEADER_USER_AGENT);
            String ip = request.getHeader(REQUESTINFO_HEADER_IP);
            String md5 = request.getHeader(REQUESTINFO_HEADER_Content_MD5);
            String contentType = request.getHeader(REQUESTINFO_HEADER_ContentType);
            String timestamp = request.getHeader(REQUESTINFO_HEADER_TIMESTAMP);
            String appbuild = request.getHeader(REQUESTINFO_HEADER_APPBUILD);
            if (contentType != null)
                contentType = contentType.toLowerCase();
            headers.put(REQUESTINFO_HEADER_UDID, udid);
            headers.put(REQUESTINFO_HEADER_UID, uid);
            headers.put(REQUESTINFO_HEADER_TOKEN, token);
            headers.put(REQUESTINFO_HEADER_SIGN, sign);
            headers.put(REQUESTINFO_HEADER_USER_AGENT, User_Agent);
            headers.put(REQUESTINFO_HEADER_APPBUILD, appbuild);
            headers.put(REQUESTINFO_HEADER_IP, ip);
            headers.put(REQUESTINFO_HEADER_Content_MD5, md5);
            headers.put(REQUESTINFO_HEADER_ContentType, contentType == null ? null : contentType);
            headers.put(REQUESTINFO_HEADER_TIMESTAMP, timestamp);

            // charset
            if (method.equals("POST") && (contentType == null || !contentType.contains("charset=utf-8") && !contentType.contains("multipart/form-data")))
                return "POST header not contains utf8 or multipart:" + contentType;

            // uid
            if (method.equals("POST") && (StaticToolit.isEmpty(uid) || !StaticToolit.isNumeric(uid)))
                return "uid error=" + uid;

            // ...


            return VERIFY_YES;
        }

        public boolean isAppCML() {
            if (headers.containsKey("app") && !StringUtils.isEmpty(headers.get("app"))) {
                return TypeUtil.strValue(headers.get("app")).equals("cml");
            }
            return false;
        }

        public boolean verifyHttps() {
            return ("https".equals(request.getScheme()));
        }

        /**
         * 判断版本号是否在xx版本以后, 包括xx版本
         *
         * @return
         */
        public boolean verifyVersion(int iosVersion, int androidVersion) {
            String buildStr = headers.get(REQUESTINFO_HEADER_APPBUILD);
            if (!StaticToolit.isEmpty(buildStr)) {
                String[] vers = buildStr.split(",");
                if (vers.length == 2) {
                    String plat = vers[0];
                    int version = TypeUtil.integerValue(vers[1]);
                    if (plat.equals("ios")) {
                        return version >= iosVersion;
                    } else if (plat.equals("android")) {
                        return version >= androidVersion;
                    }
                }
            }
            return false;
        }


        public String getIpAddr(){
            try {
                String ip = request.getHeader("X-Real-IP");
                if (!StringUtils.isBlank(ip) && !"unknown".equalsIgnoreCase(ip)) {
                    return ip;
                }
                ip = request.getHeader("X-Forwarded-For");
                if (!StringUtils.isBlank(ip) && !"unknown".equalsIgnoreCase(ip)) {
                    // 多次反向代理后会有多个IP值，第一个为真实IP。
                    int index = ip.indexOf(',');
                    if (index != -1) {
                        return ip.substring(0, index);
                    } else {
                        return ip;
                    }
                } else {
                    return "127.0.0.1";
                    // 有可能是ipv6
                    //return request.getRemoteAddr();
                }
            } catch (Exception e) {
                return "127.0.0.1";
            }
        }

        /**
         * 验证名字是否合法，目前仅仅判断是否包括（车盟，官方）这2个关键字
         *
         * @return
         */
        public String verifyName(String name) {
            if (null != name) {
                name = name.replace(" ", "");
                if (name.length() > 0) {
                    if (name.contains("车盟") || name.contains("官方")) {
                        return "昵称包含非法字符";
                    }
                    return VERIFY_YES;
                }
            }
            return "名称不能为空";
        }


        /**
         * verify vital post request:pass, if result equals {verify_yes}
         * @param postjson
         * @return
         */
        public String verifyVitalPost(String postjson) {
            String prefix = "speed";
            String sep = "-";
            String uid = headers.get(REQUESTINFO_HEADER_UID);
            String timestamp = headers.get(REQUESTINFO_HEADER_TIMESTAMP);
            String sign = headers.get(REQUESTINFO_HEADER_SIGN);
            if (uid == null || timestamp == null || postjson == null || sign == null)
                return VERIFY_NO;
            String thisString = prefix + sep + uid + sep + timestamp + sep + secretkey + sep + postjson;

            String thismd5 = Encodings.GetMD5Code16(thisString);
            if (thismd5 != null && thismd5.equals(sign))
                return VERIFY_YES;
            return VERIFY_NO;
        }
    }
    
    //main=============================================================================================
    public static void main(String[] args) {

    }
	@Override
	protected String verifyJson(String postJson, String... para) {
		throw new UnsupportedOperationException();
	}
	@Override
	protected <T> Pair<String, T> verifyJson(String postJson, Class<T> clazz, String... para) {
		throw new UnsupportedOperationException();
	}


    
    


    



}
